﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using WI.CandidateManager.Common.Data.Entities;
using WI.CandidateManager.Common.Data.Enums;

namespace WI.CandidateManager.Business.Objects
{
    public class GroupBO : BOBase
    {
        #region ManageGroup

        /// <summary>
        /// Deletes the group.
        /// </summary>
        /// <param name="groupId">The group id.</param>
        /// <returns></returns>
        public bool DeleteGroup(long groupId)
        {
            try
            {
                var group = DataContext.StudyGroupSet.Single(g => g.Id == groupId);
                foreach (var schedule in group.Schedules)
                {
                    foreach (var occurrence in schedule.Occurrences)
                    {
                        new OccurrenceBO().DeleteOccurence(occurrence.Id);
                    }
                    new ScheduleBO().DeleteSchedule(schedule.SubjectId, schedule.StudyGroupId);
                }
                group.State = State.Deleted;
                DataContext.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(String.Format("Can't delete group (groupId: {0})", groupId), ex);
                return false;
            }
        }

        /// <summary>
        /// Gets the study groups.
        /// </summary>
        /// <param name="groupId">The group id.</param>
        /// <param name="candidateId">The candidate id.</param>
        /// <param name="coachId">The coach id.</param>
        /// <returns></returns>
        public IEnumerable<StudyGroup> GetStudyGroups(long? groupId = null, long? candidateId = null, long? coachId = null)
        {
            return DataContext.StudyGroupSet
                .Where(g =>
                    (!groupId.HasValue || g.Id == groupId) &&
                    (!candidateId.HasValue || g.Candidate.Any(c => c.Id == candidateId)) &&
                    (!coachId.HasValue || g.Couch.Any(c => c.Id == coachId)) &&
                    (g.State == State.Active));
        }

        /// <summary>
        /// Saves the group.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <returns></returns>
        public bool SaveGroup(StudyGroup group)
        {
            try
            {
                Logger.Info("Try to save group");
                if (group.Id > 0)
                {
                    Logger.Info("Try to update group by Coach");
                    ApplyChanges(group);
                }
                else
                {
                    Logger.Info("Try to create group by Coach");
                    DataContext.StudyGroupSet.Add(group);
                }
                DataContext.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error("Can't added group", ex);
                return false;
            }
        }

        /// <summary>
        /// Applies the changes.
        /// </summary>
        /// <param name="studyGroup">The study group.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">studyGroup</exception>
        /// <exception cref="System.InvalidOperationException">StudyGroupId must be setted before apply changes</exception>
        protected StudyGroup ApplyChanges(StudyGroup studyGroup)
        {
            if (studyGroup == null)
            {
                throw new ArgumentNullException("studyGroup");
            }
            if (studyGroup.Id <= 0)
            {
                throw new InvalidOperationException("StudyGroupId must be setted before apply changes");
            }

            var group = DataContext.StudyGroupSet.Single(g => g.Id == studyGroup.Id);
            group.GroupName = studyGroup.GroupName;
            group.Description = studyGroup.Description;
            group.State = studyGroup.State;
            group.Couch.Clear();
            foreach (var coach in studyGroup.Couch)
            {
                group.Couch.Add(coach);
            }
            DataContext.Entry(group).State = EntityState.Modified;
            return group;
        }

        #endregion

        #region GroupCandidate

        /// <summary>
        /// Deletes the candidate from group.
        /// </summary>
        /// <param name="candidateId">The candidate id.</param>
        /// <param name="studyGroupId">The study group id.</param>
        /// <returns></returns>
        public bool DeleteCandidateFromGroup(long candidateId, long studyGroupId)
        {
            try
            {
                var group = DataContext.StudyGroupSet.Where(g => g.Id == studyGroupId).Single();
                CandidateBO candidateBO = new CandidateBO();
                var candidate = candidateBO.GetCandidates(candidateId).Single();
                group.Candidate.Remove(candidate);
                DataContext.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(String.Format("Can't delete candidate from group (groupId: {0})", studyGroupId), ex);
                return false;
            }
        }

        /// <summary>
        /// Adds the candidate to group.
        /// </summary>
        /// <param name="candidateId">The candidate id.</param>
        /// <param name="studyGroupId">The study group id.</param>
        /// <returns></returns>
        public bool AddCandidateToGroup(long candidateId, long studyGroupId)
        {
            try
            {
                var group = DataContext.StudyGroupSet.Where(g => g.Id == studyGroupId).Single();
                CandidateBO candidateBO = new CandidateBO();
                var candidate = candidateBO.GetCandidates(candidateId).Single();
                group.Candidate.Add(candidate);
                DataContext.SaveChanges();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(String.Format("Can't add candidate to group (groupId: {0})", studyGroupId), ex);
                return false;
            }
        }

        #endregion

    }
}
